﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using CSJ2K.Util.IO;

namespace CSJ2K.Jpc.Segments
{
    /// <summary>Coding style default (COD)</summary>
    /// <comment>
    /// Function: Describes the coding style, number of decomposition levels, and layering 
    ///      that is the default used for compressing all components of an image (if in the 
    ///      main header) or a tile (if in the tile-part header). The parameter values can 
    ///      be overridden for an individual component by a COC marker segment in either the
    ///      main or tile-part header.  
    /// Usage: Main and first tile-part header of a given tile. Shall be one and only one in 
    ///      the main header. Additionally, there may be at most one for each tile. If there 
    ///      are multiple tile-parts in a tile, and this marker segment is present, it shall 
    ///      be found only in the first tile-part (TPsot = 0). When used in the main header, 
    ///      the COD marker segment parameter values are used for all tile-components that do 
    ///      not have a corresponding COC marker segment in either the main or tile-part 
    ///      header. When used in the tile-part header it overrides the main header COD and 
    ///      COCs and is used for all components in that tile without a corresponding COC
    ///      marker segment in the tile-part. Thus, the order of precedence is the following: 
    ///          Tile-part COC > Tile-part COD > Main COC > Main COD 
    ///      where the "greater than" sign, >, means that the greater overrides the lessor 
    ///      marker segment. 
    /// Length: Variable depending on the value of Scod
    /// </comment>
    public class COD : Segment 
    {
        /// <summary>Coding style for all components.  Multiple params combined with bitwise OR.</summary>
        public CodingStyles S;

        public struct SGInfo
        {
            /// <summary>Progression Order</summary>
            public ProgressionOrders A;

            /// <summary>Number of Layers</summary>
            public ushort B;

            /// <summary>Multiple Component Transformation.  True=0x01 False=0x00</summary>
            public byte C;
        }
        /// <summary>Parameters for coding style designated in Scod.</summary>
        public SGInfo SG = new SGInfo();

        public struct SPInfo
        {
            /// <summary>Number of decomposition levels</summary>
            public byte D;

            /// <summary>Code-block width exponent offset value (width=2^2+E)</summary>
            public byte E;

            /// <summary>Code-block height exponent offset value (width=2^2+F)</summary>
            public byte F;

            /// <summary>Code-block style (byte)</summary>
            public CodeBlockStyles G;

            /// <summary>Transformation (byte)</summary>
            public Transformations H;

            /// <summary>Precinct size. Number depends on number of decomposition levels, COD.SP.D.</summary>
            public byte[] I;            
        }
        /// <summary>Parameters for coding style designated in Scod.</summary>
        public SPInfo SP = new SPInfo();

        public COD(Stream source)
            : this(source, (Markers)StreamUtil.ReadBUInt16(source)) { }
        public COD(Stream source, Markers marker)
            : base(source, marker, true)
        {
            if (marker != Markers.COD) throw (new ApplicationException("Attempting to create segment of the wrong type."));

            S = (CodingStyles)StreamUtil.ReadOctet(source);
            if (S != (CodingStyles)0x00)
            {
                Debug.WriteLine("Coding Styles:");
                Debug.Indent();
                for (int i = 0; i < 8; i++)
                {
                    CodingStyles style = (CodingStyles)(0x01 << i);
                    if ((S & style) == style) Debug.WriteLine(style.ToString());
                }
                Debug.Unindent();
            }
            else Debug.WriteLine("Coding Styles: None");
            SG.A = (ProgressionOrders)StreamUtil.ReadOctet(source);
            Debug.WriteLine("Progression Order: " + SG.A.ToString());
            SG.B = StreamUtil.ReadBUInt16(source);
            Debug.WriteLine("Layers: " + SG.B);
            SG.C = StreamUtil.ReadOctet(source);
            Debug.WriteLine("Multiple Component Transformation: " + (SG.C > 0));

            SP.D = StreamUtil.ReadOctet(source);
            Debug.WriteLine("Decomposition Levels: " + SP.D + "(" + (SP.D + 1) + " Resolution Levels)");
            SP.E = StreamUtil.ReadOctet(source);
            SP.F = StreamUtil.ReadOctet(source);
            Debug.WriteLine("Code-block Size: " + Math.Pow(2, 2 + SP.E) + "x" + Math.Pow(2, 2 + SP.F));
            SP.G = (CodeBlockStyles)StreamUtil.ReadOctet(source);
            Debug.WriteLine("Code-block Styles: 0x" + SP.G.ToString("X"));
            Debug.Indent();
            for (int i = 0; i < 8; i++)
            {
                CodeBlockStyles style = (CodeBlockStyles)(0x01 << i);
                if ((SP.G & style) == style) Debug.WriteLine(style.ToString());
            }
            Debug.Unindent();
            SP.H = (Transformations)StreamUtil.ReadOctet(source);
            Debug.WriteLine("Transformations: " + SP.H.ToString());

            if ((S & CodingStyles.Defined) == CodingStyles.Defined)
            {
                Debug.WriteLine("Precinct bytes: " + SP.D);
                SP.I = StreamUtil.ReadBytes(source, SP.D);
            }
            else Debug.WriteLine("Precinct bytes: 0");
        }
    }
}
